#ifndef JIAJIA_JJTOKEN_HPP
#define JIAJIA_JJTOKEN_HPP

#include"jiajiastd.hpp"
#include"jjsrc.hpp"

namespace jiajia{

    class jjtoken{
    public:
        size_t text;
        size_t size;
        word_t word;
        int rows;
        int cols;

        jjtoken():
            text(0),
            size(0),
            word(lmcc::_empty),
            rows(0),
            cols(0)
        {}

        jjtoken(size_t t, size_t s, const word_t w, const int r, const int c):
            text(t),
            size(s),
            word(w),
            rows(r),
            cols(c)
        {}

        jjtoken(const jjtoken & rhs):
            text(rhs.text),
            size(rhs.size),
            word(rhs.word),
            rows(rhs.rows),
            cols(rhs.cols)
        {}

        jjtoken & operator=(const jjtoken & rhs){
            text = rhs.text;
            size = rhs.size;
            word = rhs.word;
            rows = rhs.rows;
            cols = rhs.cols;
            return *this;
        }

        jjtoken(jjtoken && rhs):
            text(rhs.text),
            size(rhs.size),
            word(rhs.word),
            rows(rhs.rows),
            cols(rhs.cols)
        {}

        jjtoken & operator=(jjtoken && rhs){
            text = rhs.text;
            size = rhs.size;
            word = rhs.word;
            rows = rhs.rows;
            cols = rhs.cols;
            return *this;
        }

        void put(my::ubuffer & buf){
            src.put(buf, text, size, rows, cols);
        }

        my::ustring getSrc() const {
            return src.get(text, size);
        }

        std::string getLog() const {
            std::string s;
            s.append("第")
                .append(std::to_string(rows))
                .append("行, 第")
                .append(std::to_string(cols))
                .append("列中: \"")
                .append(src.get(text, size).toString())
                .append("\"");
            return s;
        }

        bool parseFalse(value_t * val) const {
            val->setConstBool(false);
            return true;
        }

        bool parseTrue(value_t * val) const {
            val->setConstBool(true);
            return true;
        }

        // 解析浮点数
        bool parseReal(value_t * val) const {
            if(val == nullptr) return false;
            if(word != lmcc::_realnum) return false;

            const my::unicode_t * u = src.getPtr(text);
            bool int_flag = true; // 整数部分 flag
            real_t sum = 0.0;
            real_t decimal = 1.0;
            real_t cur = 0;

            for(size_t i = 0; i < size; ++i){
                my::unicode_t c = my::unicode::ToHalf(u[i]);
                if(c >= my::unicode::_0 && c <= my::unicode::_9){
                    cur = (real_t)(c - my::unicode::_0);
                    if(int_flag)
                        sum = sum * 10.0 + cur;
                    else{
                        decimal /= 10;
                        sum += decimal * cur;
                    }
                }else if(c == (my::unicode_t)'.'){
                    int_flag = false;
                }else break;
            }

            val->setConstReal(sum);
            return true;
        }

        bool parseStr(value_t * val) const {
            if(val == nullptr) return false;
            if(word != lmcc::_str) return false;
            my::allocstack as;
#ifdef JIAJIA_ENABLE_DEBUG
            std::cout<<"jiajia::jjtoken::parserStr text size = "<<text.size()+1<<std::endl;
            my::unicode_t * buf = my::memory::salloc<my::unicode_t>(as, text.size()+1,
                                                                    []{std::cout<<"jiajia::jjtoken::parserStr alloc unicode buffer"<<std::endl;},
                                                                    []{std::cout<<"jiajia::jjtoken::parserStr free unicode buffer"<<std::endl;});
#else
            my::unicode_t * buf = my::memory::salloc<my::unicode_t>(as, size);
#endif
            my::unicode_t * textpt = src.getPtr(text);
            my::unicode_t * cur = buf;
            size_t forward = 0;

            while(lmcc::NEXTESCAPE(textpt, forward, *cur)){
                // std::cout<<"## "<<*cur<<", "<<my::utf8::UnicodeToStr(*cur)<<std::endl;
                ++cur;
            }
            *cur = my::unicode::empty;
            val->setConstStr(buf);
            // std::cout<<"### "<<val->getStr().toString()<<std::endl;
            return true;
        }

        bool parseValue(value_t * val){
            if(val == nullptr) return false;

            switch(word){
            case lmcc::_true: return parseTrue(val);
            case lmcc::_false: return parseFalse(val);
            case lmcc::_realnum: return parseReal(val);
            case lmcc::_str: return parseStr(val);
            default: break;
            }

            return false;
        }

        // 一些对 encode 进行分类的
        // 一些可忽略的词
        static inline bool IsIgnore(word_t w){
            return w == lmcc::_empty || w == lmcc::_blank || w == lmcc::_note;
        }

        // 一些表示常量的词
        static inline bool IsConstant(word_t w){
            return w == lmcc::_true || w == lmcc::_false ||
                w == lmcc::_realnum || w == lmcc::_str;
        }

        // 错误码
        static inline bool IsErr(word_t w){
            return w < lmcc::begin_of_err;
        }

        jjtoken & operator+=(const jjtoken & rhs){
            if(text == 0){
                (*this) = rhs;
            }else if(text < rhs.text){
                size = (rhs.text - text) + rhs.size;
            }else{
                size = (text - rhs.text) + size;
                text = rhs.text;
            }
            return *this;
        }
    };

    std::ostream & operator<<(std::ostream & os, const jjtoken & token){
        os<<"\""<<token.getSrc()<<"\", "
          <<lmcc::WORDSTR(token.word)<<", at["<<token.rows<<", "<<token.cols<<"]";
        return os;
    }
}
#endif
